//==================================================================
//  Copyright (C) 2006-2007  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
/// @file data_schema.cpp
///
///
/// @author Davide Pasca
///
//==================================================================

#ifndef DATA_SCHEMA_H
#define DATA_SCHEMA_H

#include <stdio.h>
#include "psys.h"

//==================================================================
class sha1_t
{
public:
	u_char	_data[20];

	sha1_t()
	{
		//srand( PSYS::TimerGetUL64() );
		for (int i=0; i < 20; ++i)
			_data[i] = 0;
	}

	static bool AreEqual( const u_char a[20], const u_char b[20] )
	{
		for (int i=0; i < 20; ++i)
			if ( a[i] != b[i] )
				return false;

		return true;
	}

	bool IsEmpty() const
	{
		return _data[0] == 0;
	}
};

//==================================================================
class ItemBase
{
public:
	autodel<TCHAR>	_stridp;
	autodel<TCHAR>	_strid_alternativep;

public:
	ItemBase( const TCHAR *stridp, const TCHAR *strid_alternativep=NULL )
	{
		_stridp	= strcpyalloc( stridp );
		if ( strid_alternativep )
			_strid_alternativep	= strcpyalloc( strid_alternativep );
	}

	virtual ~ItemBase(){};

	virtual void		LoadFromString( const TCHAR *strp ) = 0;
	virtual const TCHAR	*StoreToString( TCHAR *outstrp, int outstr_maxlen ) = 0;

	static TCHAR		*strcpyalloc( const TCHAR *srcp );
};

//==================================================================
class ItemString : public ItemBase
{
public:
	TCHAR	*_datap;
	int		_max_str_len;

public:
	ItemString( const TCHAR *stridp, TCHAR *datap, int strsize ) :
	  ItemBase(stridp)
	{
		_datap	 = datap;
		_max_str_len = strsize;
	}

	virtual ~ItemString(){};

	virtual void		LoadFromString( const TCHAR *strp )
	{
		_tcscpy_s( _datap, _max_str_len, strp );

	}
	virtual const TCHAR	*StoreToString( TCHAR *outstrp, int outstr_maxlen )
	{
		_tcscpy_s( outstrp, _max_str_len, _datap );
		return outstrp;
	}
};

//==================================================================
class ItemSHA1Hash : public ItemBase
{
public:
	sha1_t	*_datap;
	int		_max_str_size;

public:
	ItemSHA1Hash( const TCHAR *stridp, sha1_t *sha1hashp ) :
	  ItemBase(stridp)
	{
		_datap	 = sha1hashp;
	}

	virtual ~ItemSHA1Hash(){};

	virtual void		LoadFromString( const TCHAR *strp );
	virtual const TCHAR	*StoreToString( TCHAR *outstrp, int outstr_maxlen );
};

//==================================================================
class ItemInt : public ItemBase
{
public:
	int		*_datap;
	int		_min, _max;

public:
	ItemInt( const TCHAR *stridp, int *datap, int minval, int maxval ) :
		ItemBase(stridp),
		_datap(datap),
		_min(minval),
		_max(maxval)
	{
	}

	virtual ~ItemInt(){};

	virtual void		LoadFromString( const TCHAR *strp )
	{
		*_datap = _tcstol( strp, NULL, 10 );
		PCLAMP( *_datap, _min, _max );
	}
	virtual const TCHAR	*StoreToString( TCHAR *outstrp, int outstr_maxlen )
	{
		_stprintf_s( outstrp, outstr_maxlen, _T("%i"), *_datap );
		return outstrp;
	}
};

//==================================================================
class ItemULong : public ItemBase
{
public:
	u_long		*_datap;
	u_long		_min, _max;

public:
	ItemULong( const TCHAR *stridp, u_long *datap, u_long minval, u_long maxval ) :
		ItemBase(stridp),
		_datap(datap),
		_min(minval),
		_max(maxval)
	{
	}

	virtual ~ItemULong(){};

	virtual void		LoadFromString( const TCHAR *strp )
	{
		*_datap = _tcstoul( strp, NULL, 10 );
		PCLAMP( *_datap, _min, _max );
	}
	virtual const TCHAR	*StoreToString( TCHAR *outstrp, int outstr_maxlen )
	{
		_stprintf_s( outstrp, outstr_maxlen, _T("%lu"), *_datap );
		return outstrp;
	}
};

//==================================================================
class ItemFloat : public ItemBase
{
public:
	float		*_datap;
	float		_min, _max;

public:
	ItemFloat( const TCHAR *stridp, float *datap, float minval, float maxval ) :
		ItemBase(stridp),
		_datap(datap),
		_min(minval),
		_max(maxval)
	{
	}

	virtual ~ItemFloat(){};

	virtual void		LoadFromString( const TCHAR *strp )
	{
		*_datap = (float)_tcstod( strp, NULL );
		PCLAMP( *_datap, _min, _max );
	}
	virtual const TCHAR	*StoreToString( TCHAR *outstrp, int outstr_maxlen )
	{
		_stprintf_s( outstrp, outstr_maxlen, _T("%g"), *_datap );
		return outstrp;
	}
};

//==================================================================
class ItemBool : public ItemBase
{
public:
	bool	*_datap;

public:
	ItemBool( const TCHAR *stridp, bool *datap, const TCHAR *strid_alternativep=NULL ) :
		ItemBase(stridp, strid_alternativep),
		_datap(datap)
	{
	}

	virtual ~ItemBool(){};

	virtual void		LoadFromString( const TCHAR *strp )
	{
		*_datap = (_tcstoul( strp, NULL, 10 ) ? true : false);
	}
	virtual const TCHAR	*StoreToString( TCHAR *outstrp, int outstr_maxlen )
	{
		_stprintf_s( outstrp, outstr_maxlen, _T("%i"), *_datap ? 1 : 0 );
		return outstrp;
	}
};

//==================================================================
class DataSchema
{
public:
	std::vector<ItemBase *>	_itemsp_list;
	const TCHAR				*_stridp;

	//---------------------------------------------------------------------------
	DataSchema( const TCHAR *stridp );
	~DataSchema();

	//---------------------------------------------------------------------------
	void	AddString( const TCHAR *stridp, TCHAR *datap, int maxstrlen );
	void	AddSHA1Hash( const TCHAR *stridp, sha1_t *sha1hashp );
	void	AddInt( const TCHAR *stridp, int *datap, int i_min, int i_max );
	void	AddULong( const TCHAR *stridp, u_long *datap, u_long ul_min, u_long ul_max );
	void	AddFloat( const TCHAR *stridp, float *datap, float f_min, float f_max );
	void	AddBool( const TCHAR *stridp, bool *datap, const TCHAR *strid_alternativep=NULL );

	PError	SaveData( FILE *fp ) const;
	int		LoadData( FILE *fp );

	struct LoaderItem
	{
		const TCHAR	*_namep;
		DataSchema	*(*_Callback)( FILE *fp, void *userdatap );
		void		*_userdatap;
	};
	static int	LoadSchemas_s( FILE *fp, LoaderItem *loader_itemsp, int n_loader_items );

private:
	ItemBase	*item_find_by_strid( const TCHAR *stridp );
};

#endif